using System;
using System.Collections.Generic;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using ITAP.ShprossesBuilder.Modelling.Components;
using ITAP.ShprossesBuilder.Render;
using ITAP.ShprossesBuilder.Modelling;
using ITAP.ShprossesBuilder.Calculations;
using System.Globalization;
using ITAP.ShprossesBuilder.Calculations.CoordinateTransformations;
using ITAP.ShprossesBuilder.Editor;
using ITAP.ShprossesBuilder.Manipulation.Tolerance;
using ITAP.ShprossesBuilder.Manipulation;
using ITAP.Core.Modelling;
using ITAP.Core.Calculations;

namespace ITAP.ShprossesBuilder
{
    public partial class ModelControl : Panel
    {
        private ModelManipulator manipulator;

        public ModelManipulator Manipulator
        {
            get { return manipulator; }
           // set { manipulator = value; }
        }

        private ToleranceManager toleranceManager;

        public ToleranceManager ToleranceManager
        {
            get { return toleranceManager; }
        }

        private ProfilesProviderDelegate profileProvider;

        public ProfilesProviderDelegate ProfileProvider
        {
            get { return profileProvider; }
        }

        private Font mouseKeyFont = new Font("Courier New", 14);
        private string mouseKeyCombination = "";

        public string MouseKeyCombination
        {
            get { return mouseKeyCombination; }
            set { mouseKeyCombination = value; }
        }

        private ICoordinateTransformer coordinateTransformer = new GlobalToInnerSpacerCoordinateTransformer();

        public ICoordinateTransformer CoordinateTransformer
        {
            get { return coordinateTransformer; }
            set { coordinateTransformer = value; }
        }

        private bool drawCross = false;

        public bool DrawCross
        {
            get { return drawCross; }
            set { drawCross = value; }
        }
        private bool drawCrossPosition = false;

        public bool DrawCrossPosition
        {
            get { return drawCrossPosition; }
            set { drawCrossPosition = value; }
        }

        public bool UseAutoScale
        {
            get
            {
                return coordinateConverter.UseAutoScale;
            }
            set
            {
                coordinateConverter.UseAutoScale = value;
            }
        }

        public double ModelScale
        {
            get
            {
                return coordinateConverter.Scale;
            }
            set
            {
                coordinateConverter.Scale = value;
            }
        }

        private ModelPoint camera;

        public ModelPoint Camera
        {
            get { return camera; }
            set { camera = value; }
        }

        public RectangleF FullRectangle
        {
            get
            {
                return modelContainer.BoundingBox;
            }
        }

        public void DeselectAll()
        {
            foreach (IComponent innerComponent in modelContainer.AllInnerComponents)
                innerComponent.Selected = false;
            modelContainer.SelectedComponentsStack.Clear();
        }

        public RectangleF VisibleRectangle
        {
            get
            {
                PointF centerScreenPoint = coordinateConverter.ModelPointToScreenPoint(camera, this.ClientRectangle.Width, this.ClientRectangle.Height, modelContainer.BoundingBox, camera);
                double width = coordinateConverter.ScreenMeasureToModelMeasure(this.ClientRectangle.Width, this.ClientRectangle.Width, this.ClientRectangle.Height, modelContainer.BoundingBox);
                double height = coordinateConverter.ScreenMeasureToModelMeasure(this.ClientRectangle.Height, this.ClientRectangle.Width, this.ClientRectangle.Height, modelContainer.BoundingBox);
                return new RectangleF((float)(camera.X - width / 2), (float)(camera.Y - height / 2), (float)width, (float)height);

            }
        }

        private ModelCoordinateConverter coordinateConverter = new ModelCoordinateConverter();

        public ModelCoordinateConverter CoordinateConverter
        {
            get { return coordinateConverter; }
            set { coordinateConverter = value; }
        }

        //public bool EnableDimensions
        //{
        //    get
        //    {
        //        return modelContainer.EnableDimensions;
        //    }
        //    set
        //    {
        //        modelContainer.EnableDimensions = value;
        //        this.Invalidate();
        //    }
        //}

        private ModelContainer modelContainer;

        public ModelContainer ModelContainer
        {
            get { return modelContainer; }
            set 
            { 
                modelContainer = value;
                //if(modelContainer != null)
                //    this.camera = new ModelPoint(modelContainer.BoundingBox.Width / 2, modelContainer.BoundingBox.Height / 2);
            }
        }

        private SimpleRender _render = new SimpleRender();
        public SimpleRender Render
        {
            get { return _render; }
            set { _render = value; }
        }

        public ModelControl()
        {            
            InitializeComponent();
            toleranceManager = new ToleranceManager();
            manipulator = new ModelManipulator(this);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            coordinateConverter = new ModelCoordinateConverter();

            this.Camera = new ModelPoint(0, 0);
        }

        public void SetCameraToCenter()
        {
            RectangleF rect = this.modelContainer.BoundingBox;
            this.Camera = new ModelPoint(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
        }

        internal void SetProfileProvider(ProfilesProviderDelegate profileProvider)
        {
            this.profileProvider = profileProvider;
        }

        public void UpdateModel()
        {
            this.ModelContainer.Update();
            this.Invalidate();
        }

        internal PointF ModelToScreen(ModelPoint point)
        {
            if (this.camera == null)
                return new Point(0, 0);
            RectangleF bbox = this.ModelContainer.BoundingBox;
            PointF screenPoint = this.CoordinateConverter.ModelPointToScreenPoint(point, this.ClientRectangle.Size.Width, this.ClientRectangle.Size.Height, bbox, this.Camera);
            return screenPoint;
        }

        internal ModelPoint ScreenToModel(PointF point)
        {
            if (this.camera == null)
                return new ModelPoint(0, 0);
            RectangleF bbox = this.ModelContainer.BoundingBox;
            ModelPoint modelPoint = this.CoordinateConverter.ScreenPointToModelPoint(point, this.ClientRectangle.Size.Width, this.ClientRectangle.Size.Height, bbox, this.Camera);
            return modelPoint;
        }


        public void ZoomIn(ModelPoint centerPoint, double scaleDelta)
        {            
            this.Camera = (ModelPoint)centerPoint.Clone();
            this.ModelScale /= scaleDelta;
            this.Invalidate();
        }

        public void ZoomOut(ModelPoint centerPoint, double scaleDelta)
        {
            this.Camera = (ModelPoint)centerPoint.Clone();
            this.ModelScale *= scaleDelta;
            this.Invalidate();
        }


        private void ModelControl_Paint(object sender, PaintEventArgs e)
        {
            if (modelContainer == null) 
                return;

            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            if (modelContainer != null)
            {    
                RectangleF modelBBox = modelContainer.BoundingBox;
                if (camera == null)
                    camera = new ModelPoint(modelBBox.Width / 2, modelBBox.Height / 2);

                _render.ScreenRectangle = coordinateConverter.ModelRectangleToScreenRectangle(this.VisibleRectangle, this.ClientRectangle.Width, this.ClientRectangle.Height, modelBBox, camera);
                _render.Initialize(e.Graphics, this.ClientRectangle.Width, this.ClientRectangle.Height, modelBBox, coordinateConverter, camera);
                
                modelContainer.AcceptVisitor(_render);
                RectangleF visibleRectangle = this.VisibleRectangle;

                if (drawCross)
                {
                    Pen pen = new Pen(Color.FromArgb(100, 100, 100, 100));
                    Point xStartPoint = new Point(this.ClientRectangle.Width / 2 - 10, this.ClientRectangle.Height / 2);
                    Point xEndPoint = new Point(this.ClientRectangle.Width / 2 + 10, this.ClientRectangle.Height / 2);

                    Point yStartPoint = new Point(this.ClientRectangle.Width / 2, this.ClientRectangle.Height / 2 - 10);
                    Point yEndPoint = new Point(this.ClientRectangle.Width / 2, this.ClientRectangle.Height / 2 + 10);
                    e.Graphics.DrawLine(pen, xStartPoint, xEndPoint);
                    e.Graphics.DrawLine(pen, yStartPoint, yEndPoint);
                    pen.Dispose();

                    if (drawCrossPosition && this.modelContainer.ActiveCell != null)
                    {
                        CultureInfo culture = new CultureInfo("en-US");                        
                        RectangleF cellBBox = this.modelContainer.ActiveCell.BoundingBox;
                        ModelPoint activeCellCameraPosition = new ModelPoint(camera.X, camera.Y);

                        ModelPoint point = coordinateTransformer.TransformTo(this.modelContainer, activeCellCameraPosition);

                        string position = point.X.ToString("0.0", culture) + " " + point.Y.ToString("0.0", culture);                        
                        Font font = new Font("Courier New", 8);
                        e.Graphics.DrawString(position, font, Brushes.Black, xEndPoint.X - 7, yEndPoint.Y - 7);
                    }
                }

                //if (mouseKeyCombination != "")
                //{
                //    e.Graphics.DrawString(mouseKeyCombination, mouseKeyFont, Brushes.Black, 10, this.ClientRectangle.Height - 40);
                //}

            }
        }

        private void ModelControl_MouseClick(object sender, MouseEventArgs e)
        {
            
        }

        private void ModelControl_Resize(object sender, EventArgs e)
        {
        }
    }
}
